"""
业务层
"""

# flake8: noqa

from pydantic import (
    BaseModel,
    ValidationError,
)
from typing_extensions import deprecated

import utils.enum_utils as enum
from components.logger import log
from mapping.base_mapping import (
    MappingBase,
    TMapping,
)
from models import (
    PageQuery,
    POBase,
    POPage,
    TRequest,
    TVO,
    VOPage,
)
from my_typing import *
from service.base import (
    TPO,
    ServiceBase,
    TService,
)
from utils.data_utils import create_model_from_function
from utils.data_utils.special import ObjectIdStr
from utils.exception_utils import BusinessError


class ValidatorBase:
    """ 校验器 | 基类 """

    model_id_field: str = "id"
    """ 模型 ID 字段 """

    model_name: str = "实例"
    """ 模型名称 """

    model_po: type[TPO] = POBase
    """ 模型 | PO """

    model_service: type[TService] = ServiceBase
    """ 模型 | 数据层 """

    # -------------------- is_xxx --------------------
    @classmethod
    def is_mine(
        cls,
        id: ObjectIdStr | None,  # noqa: ignore[built-in name]
        user_id: ObjectIdStr | None,
    ) -> bool:
        """
        校验实例是否属于当前用户

        Args:
            id: 模型 ID
            user_id: 用户 ID

        Returns:
            True / False
        """

        if (
            not id
            or not user_id
        ):
            return False

        model_po: TPO | None = cls.model_service.get_one_by_id(id)

        if not model_po:
            return False

        return model_po.user_id == user_id

    # -------------------- validate_xxx --------------------

    @classmethod
    def validate_exist(cls, id: ObjectIdStr) -> None:  # noqa: ignore[built-in name]
        """ 根据 ID 校验实例是否存在 """

        if not cls.model_service.exists_by_id(id):
            raise BusinessError(f"{cls.model_name} ID <{id}> 不存在")

    @classmethod
    def validate_mine(
        cls,
        id: ObjectIdStr,  # noqa: ignore[built-in name]
        user_id: ObjectIdStr | None,
    ) -> None:
        """ 校验实例是否属于当前用户 """

        if not cls.is_mine(id, user_id):
            raise BusinessError(f"{cls.model_name} ID <{id}> 不属于当前用户")

    @classmethod
    def validate_exist_batch(cls, id_list: Iterable[ObjectIdStr]) -> None:
        """ 根据 ID 列表校验实例是否存在 """

        if not id_list:
            return None

        exist_id_list: list[ObjectIdStr] = cls.model_service.get_distinct_id_list(id_list)

        if invalid_ids := set(id_list) - set(exist_id_list):
            raise BusinessError(f"{cls.model_name} ID <{'、'.join(invalid_ids)}> 不存在")

    @classmethod
    def validate_exist_by_request(cls, request: TRequest) -> None:
        """ 根据请求体 校验实例是否存在（根据模型 ID） """

        model_id: ObjectIdStr | None = getattr(request, cls.model_id_field, None)

        if model_id is None:
            raise BusinessError(f"{cls.model_name} ID 参数 <{cls.model_id_field}> 缺失")

        cls.validate_exist(model_id)

    @classmethod
    def validate_union(
        cls,
        params: dict,
        *validators,
    ) -> None:
        """
        联合执行所有校验器，捕捉到异常后统一抛出异常

        注意点：
            1. 校验器只能通过关键字传参
            2. 校验器的参数无需加 `**kwargs`

        Args:
            params: 校验器需要用到的参数
            *validators: 校验器

        Raises:
            BusinessError
        """

        if not validators:
            return None

        errors: ListStr = []

        for validator in validators:
            try:
                validator_param_model: type[BaseModel] = create_model_from_function(validator)
                param_instance: BaseModel = validator_param_model(**params)
                validator(**param_instance.model_dump())

            except BusinessError as be:
                errors += be.errors

            except ValidationError as ve:
                log.error(f"[联合校验失败] 校验器：{validator.__name__}，错误信息：{ve.errors()}")
                raise ve

        if errors:
            raise BusinessError(errors)

    # -------------------- validate_crud --------------------

    @classmethod
    def validate_detail(cls, request: TRequest) -> None:
        """ 校验 | 详情 """

        cls.validate_exist_by_request(request)


class GetterBase:
    """ 获取器 | 基类 """

    model_validator: type[ValidatorBase] = ValidatorBase
    """ 校验器 """

    model_mapping: type[TMapping] = MappingBase
    """ 模型 | 映射 """

    @classmethod
    def detail(cls, request: TRequest) -> TVO:
        """ 详情 """

        cls.model_validator.validate_detail(request)
        model_id: ObjectIdStr | None = getattr(request, cls.model_validator.model_id_field, None)
        po: TPO = cls.model_validator.model_service.get_one_by_id(model_id)
        vo: TVO = cls.model_mapping.po_2_detail_vo(po)

        return vo

    @classmethod
    def list(cls, request: TRequest) -> VOPage[TPO]:
        """ 列表 """

        page_query: PageQuery = cls.get_list_page_query(request)
        po_page: POPage[TPO] = cls.model_validator.model_service.paginated_query(page_query)
        vo_page: VOPage[TVO] = cls.model_mapping.po_page_2_vo_page(po_page)

        return vo_page

    @classmethod
    def get_list_page_query(cls, request: TRequest) -> PageQuery:
        """ 获取列表的分页查询条件 """

        return PageQuery(
            page=request.page,
            page_size=request.page_size,
            sorting=cls.get_list_sorting(request),
            query=cls.get_list_query(request),
        )

    @staticmethod
    def get_list_sorting(request: TRequest) -> DictStrInt:
        """ 获取列表排序字段映射（如果查询的字段是嵌套的，或者和字段名不一致的，需要重写） """

        return request.get_sorting_dict()

    @staticmethod
    def get_list_query(request: TRequest) -> dict:
        """ 获取列表查询条件 """

        raise NotImplemented("继承 GetterBase 的子类需要实现 get_list_query 方法")

    class Condition:
        """ 查询条件 """

        def __init__(
            self,
            query: DictOrNone = None,
        ) -> None:
            self.__query: dict = query or {}
            """ 最终的查询条件 """

            self.__and_list: list[dict] = []
            """ 所有查询条件用 $and 连接（MongoDB 会自动优化连接符内的查询条件） """

            if self.__query:
                self.__and_list.append(self.__query)

        def get_query(self) -> dict:
            """ 获取最终的查询条件 """

            if not self.__and_list:
                return {}

            return {"$and": self.__and_list}

        @staticmethod
        def __get_value(
            value: Any,
            func: CallableAny | None = None,
        ) -> Any:
            if func is not None:
                return func(value)

            return value

        def __add_query(
            self,
            expression: str,
            field: str,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 查询

            Args:
                expression: 表达式
                field: 字段名
                value: 值
                func: 额外的转换函数
            """

            if value is None:
                return

            self.__and_list.append(
                {
                    field: {
                        expression: self.__get_value(value, func)
                    }
                }
            )

        def add_eq(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 精确查询

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$eq", field, value, func)

        def add_ne(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 不等于

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$ne", field, value, func)

        def add_regex(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 模糊查询

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$regex", field, value, func)

        def add_gt(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 大于

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            if value is None:
                return

            self.__add_query("$gt", field, value, func)

        def add_gte(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 大于等于

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$gte", field, value, func)

        def add_lt(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 小于

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$lt", field, value, func)

        def add_in(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 在...范围内

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$in", field, value, func)

        def add_nin(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 不在...范围内

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$nin", field, value, func)

        def add_lte(
            self,
            field: str,
            *,
            value: Any,
            func: CallableAny | None = None,
        ) -> None:
            """
            添加 小于等于

            Args:
                field: 字段名（可以是嵌套的，用 `.` 连接）
                value: 值
                func: 额外的转换函数
            """

            self.__add_query("$lte", field, value, func)

        def add_custom_query(
            self,
            *,
            value: Any,
            query: dict,
        ) -> None:
            """
            添加 自定义的查询条件

            Args:
                value: 值
                query: 自定义查询条件
            """

            if value is None:
                return

            self.__and_list.append(query)


class DeleterBase:
    """ 删除器 | 基类 """

    @staticmethod
    @deprecated("🚨该方法已弃用，替换成对应模型 Validator中的 `validate_delete`")
    def validate_delete(request: TRequest) -> None:
        """ 校验 | 删除 """

        raise NotImplemented("继承 DeleterBase 的子类需要实现 validate_delete 方法")

    @staticmethod
    def version_log(model_po: TPO) -> None:
        """
        添加版本日志

        Args:
            model_po: PO (删除前的)
        """

        from biz.model_version_biz import VersionSetter

        VersionSetter.async_create_version(
            old_po=model_po,
            model_operation=enum.ModelOperation.DELETE,
            po_operation=enum.POOperation.DELETE,
        )


class CreatorBase:
    """ 创建器 | 基类 """

    @staticmethod
    @deprecated("🚨该方法已弃用，替换成对应模型 Validator中的 `validate_create`")
    def validate_create(request: TRequest) -> None:
        """ 校验 | 创建 """

        raise NotImplemented("继承 CreatorBase 的子类需要实现 validate_create 方法")

    @staticmethod
    def version_log(
        model_po: TPO,
        model_operation: enum.ModelOperation = enum.ModelOperation.CREATE,
        po_operation: enum.POOperation = enum.POOperation.CREATE,
    ) -> None:
        """
        添加版本日志

        Args:
            model_po: PO (新建的)
            model_operation: 模型操作类型
            po_operation: PO 操作类型
        """

        from biz.model_version_biz import VersionSetter

        VersionSetter.async_create_version(
            new_po=model_po,
            model_operation=model_operation,
            po_operation=po_operation,
        )


class UpdatorBase:
    """ 更新器 | 基类 """

    @staticmethod
    @deprecated("🚨该方法已弃用，替换成对应模型 Validator中的 `validate_update`")
    def validate_update(request: TRequest) -> None:
        """ 校验 | 更新 """

        raise NotImplemented("继承 UpdatorBase 的子类需要实现 validate_update 方法")

    @staticmethod
    def version_log(
        old_po: TPO,
        new_po: TPO,
        *,
        model_operation: enum.ModelOperation = enum.ModelOperation.UPDATE,
        po_operation: enum.POOperation = enum.POOperation.UPDATE,
    ) -> None:
        """
        添加版本日志

        Args:
            old_po: PO (更新前的)
            new_po: PO (更新后的)
            model_operation: 模型操作类型
            po_operation: PO 操作类型
        """

        from biz.model_version_biz import VersionSetter

        VersionSetter.async_create_version(
            old_po=old_po,
            new_po=new_po,
            model_operation=model_operation,
            po_operation=po_operation,
        )
